import {
    MainElement,
    SchemaArrayElement,
    SimpleArrayElement,
    SchemaKeyElement,
    SchemaObjectElement,
    SimpleObjectElement,
    SchemaTypeElement,
    SchemaValueElement,
    StructElement
} from "../server/schema-element";

export interface DslType {}
export interface DslNamedType extends DslType {
    typeName: string;
    createInitElement(parentElement: StructElement): MainElement;
}
export function isNamedType(type: DslType): type is DslNamedType {
    return type.hasOwnProperty('typeName');
}

/**
 * 联合类型
 */
export class DslUnionType implements DslType {
    static readonly typeMetaName = Symbol('union');
    getTypeMetaName(): Symbol {
        return DslUnionType.typeMetaName;
    }

    unionTypes: Map<string, DslType>;
    constructor() {
        this.unionTypes = new Map();
    }

    /**
     * 添加一个类型到联合类型中
     * @param typeName 类型名称
     * @param type 类型对象
     */
    union(type: DslType): this {
        if (isNamedType(type)) {
            const typeName = type.typeName;
            if (this.unionTypes.has(typeName)) {
                throw new Error(`Type name ${typeName} already exists in union type.`);
            }
            this.unionTypes.set(typeName, type);
            return this;
        } else {
            // 如果是联合类型，直接将其所有类型添加到当前联合类型中
            if (type instanceof DslUnionType) {
                type.unionTypes.forEach((t, name) => {
                    if (this.unionTypes.has(name)) {
                        throw new Error(`Type name ${name} already exists in union type.`);
                    }
                    this.unionTypes.set(name, t);
                });
                return this;
            }

            throw new Error('un support!');
        }
    }
}

/**
 * 数组类型
 */
export class DslArrayType implements DslNamedType {
    // 类型名称
    typeName: string;
    // 数组元素的类型
    itemType: DslType;

    constructor(typeName: string, itemType: DslType) {
        this.typeName = typeName;
        this.itemType = itemType;
    }

    createInitElement(parentElement: StructElement): MainElement {
        const ret: SimpleArrayElement = new SimpleArrayElement();
        ret.parentElement = parentElement;
        ret.readonly = false;

        const itemTypeName = isNamedType(this.itemType) ? this.itemType.typeName : '';
        ret.insertNextLine(1);
        ret.insertChild({
            type: 'type',
            typeName: itemTypeName,
            readonly: (!itemTypeName)
        } as SchemaTypeElement);
        if (isNamedType(this.itemType)) {
            ret.insertChild(this.itemType.createInitElement(ret));
        }
        ret.insertNextLine(0);
        return ret;
    }
}

/**
 * 基础类型
 */
export class DslAtomicType implements DslType {
    static readonly STRING_TYPE = new DslAtomicType('string');
    static readonly NUMBER_TYPE = new DslAtomicType('number');
    static readonly BOOLEAN_TYPE = new DslAtomicType('boolean');
    static readonly NULL_TYPE = new DslAtomicType('null');

    typeName: string;
    constructor(typeName: string) {
        this.typeName = typeName;
    }

    createInitElement(parentElement: StructElement): MainElement {
        if (this.typeName === 'null') {
            return {
                type: 'value',
                value: 'null',
                parentElement,
                readonly: true,
            } as SchemaValueElement;
        }

        let defaultValue = '';
        if (this.typeName === 'boolean') {
            defaultValue = 'false'; // 默认布尔值为false
        } else if (this.typeName === 'number') {
            defaultValue = '0';
        }

        return {
            type: 'value',
            value: defaultValue,
            parentElement,
            readonly: false,
        } as SchemaValueElement;
    }

    valueIsType(value: string): boolean {
        switch (this.typeName) {
            case 'string':
                return true; // 所有字符串都是string类型
            case 'number':
                return !isNaN(Number(value)); // 数字类型
            case 'boolean':
                return value === 'true' || value === 'false'; // 布尔类型
            case 'null':
                return value === 'null'; // null类型
            default:
                return false; // 其他类型不支持
        }
    }
}

/**
 * Tuple类型
 */
export class DslTupleType implements DslType {
    // 类型名称
    typeName: string;
    // 类型列表
    types: Array<DslType>;
    constructor(typeName: string, types: Array<DslType>) {
        this.typeName = typeName;
        this.types = types;
    }

    createInitElement(parentElement: StructElement): MainElement {
        const ret: SchemaArrayElement = new SimpleArrayElement();
        ret.parentElement = parentElement;

        let tupleReadonly: boolean = true;
        this.types.forEach((type) => {
            const typeName = isNamedType(type) ? type.typeName : '';
            const typeElement: SchemaTypeElement = {
                type: 'type',
                typeName: typeName,
                parentElement: ret,
                readonly: (!typeName)
            }
            if (isNamedType(type)) {
                const schemaElement = type.createInitElement(ret);
                tupleReadonly = tupleReadonly
                    && (!!typeElement.readonly)
                    && (schemaElement as any).readonly;
                ret.insertChild(typeElement);
                ret.insertChild(schemaElement);
            } else {
                tupleReadonly = false;
                ret.insertChild(typeElement);
            }
        });
        ret.readonly = tupleReadonly;
        return ret;
    }
}

/**
 * 常量类型
 */
export class DslConstType implements DslType {
    atomicType: DslAtomicType;
    value: string;
    typeName: string;

    constructor(atomicType: DslAtomicType, value: string) {
        this.atomicType = atomicType;
        this.value = value;

        this.typeName = `const ${atomicType.typeName} ${value}`;
    }

    /**
     * 创建类型的初始元素
     * @param parentElement 父元素
     * @returns value类型的只读元素
     */
    createInitElement(parentElement: StructElement): MainElement {
        return {
            type: 'value',
            value: this.value,
            parentElement,
            readonly: true,
        } as SchemaValueElement;
    }
}

/**
 * Struct类型的属性
 */
export interface DslStructField {
    name: string;
    type: DslType;
    required: boolean;
    defaultValue: string;
}

/**
 * 结构体类型
 */
export class DslStructType implements DslType {
    typeName: string;
    fields: Array<DslStructField>;
    constructor(typeName: string) {
        this.typeName = typeName;
        this.fields = [];
    }

    addField(fieldName: string, type: DslType, required: boolean, defaultValue: string) {
        const field: DslStructField = {
            name: fieldName,
            type,
            required,
            defaultValue: defaultValue
        };
        this.fields.push(field);
        return this;
    }

    require(fieldName: string, type: DslType, defaultValue?: string) {
        return this.addField(fieldName, type, true, defaultValue || '');
    }
    
    notRequire(fieldName: string, type: DslType, defaultValue?: string) {
        return this.addField(fieldName, type, false, defaultValue || '');
    }

    getField(fieldName: string): DslStructField {
        const field = this.fields.find(f => f.name === fieldName);
        if (!field) {
            throw new Error(`Field ${fieldName} not found in struct ${this.typeName}.`);
        }
        return field;
    }

    /**
     * 创建结构体类型的初始元素
     * @param parentElement 父元素
     * @returns SchemaObjectElement
     */
    createInitElement(parentElement: StructElement): MainElement {
        if (this.fields.length === 0) {
            // 如果没有字段，返回一个空的SchemaObjectElement
            const ret: SchemaObjectElement = new SimpleObjectElement();
            ret.parentElement = parentElement;
            ret.readonly = true;
            return ret;
        }

        // 存在几种情况：1、this.fields中没有字段；2、this.fields中有字段但都是只读的；3、this.fields中有字段但是没有一个有默认值或者require
        const requiredFields = this.fields.filter(field => field.required);
        if (requiredFields.length === 0) {
            const ret: SchemaObjectElement = new SimpleObjectElement();
            ret.parentElement = parentElement;
            ret.insertChild({
                type: 'type',
                typeName: '',
                readonly: false
            } as SchemaTypeElement);
            return ret;
        }
        
        const ret: SchemaObjectElement = new SimpleObjectElement();
        ret.parentElement = parentElement;
        let objectReadonly = requiredFields.length === this.fields.length;
        requiredFields.forEach(field => {
            ret.insertNextLine(1);
            ret.insertChild({
                type: 'key',
                key: field.name,
                readonly: true
            } as SchemaKeyElement);
            const fieldType = field.type;
            const fieldTypeName = isNamedType(fieldType) ? fieldType.typeName : '';

            // 如果type是unionType，那么type是可选的，此时直接创建type输入框，不创建value输入框
            ret.insertChild({
                type: 'type',
                typeName: fieldTypeName,
                readonly: (!fieldTypeName)
            } as SchemaTypeElement);
            if (isNamedType(fieldType)) {
                const value = fieldType.createInitElement(ret);
                if ((value as any).readonly === false) {
                    objectReadonly = false;
                }
                ret.insertChild(value);
            } else {
                objectReadonly = false;
            }
        });
        // 在最后插入一个nextLine元素
        ret.insertNextLine(0);
        ret.readonly = objectReadonly;
        return ret;
    }
}
